<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>脚本控件参考</title>
<style>
body{font-size:13px;}
table{border-collapse:collapse;border:1px solid #ccc;font-size:14px; }
p.code{color:#629600;}
</style>
</head>
<body>


<h3>
	<strong>21.4</strong>&nbsp; <strong>脚本控件参考</strong></h3>
<p>
	本章中间的部分将给出脚本控件的参考，包括对象、集合、属性、方法、方法语法和示例。参考之后，这一章将继续讨论一些额外的问题，然后介绍一些可下载的使用脚本控件的Visual Basic 6和VB.NET应用程序。代码和语法示例是基于VB 6的；要获得等效的语法信息，请参考.NET语言(如VB.NET或C#)的文档。从这一章中的VB.NET范例工程中可以获得与.NET相关的指导信息。</p>
<h3>
	<strong>21.4</strong>.1&nbsp; 对象模型</h3>
<p>
	脚本控件对象模型的描述如图21<strong>-</strong>1所示。对象及其属性和方法的细节将在后续的章节中详细讨论。</p>
<p>
	图21<strong>-</strong>1</p>
<h3>
	<strong>21.4</strong>.2&nbsp; 对象与集合</h3>
<p>
	脚本控件组件有几个对象和集合(这是一种特殊的多值对象)，它们协同工作，提供了大量功能用于在Visual Basic应用程序中添加脚本。对于每个对象和集合，这一节中都给出对象的一般描述，并详细介绍其属性、方法和事件。在适当的时候，给出示例代码。</p>
<h4>
	1. ScriptControl对象</h4>
<p>
	ScriptControl是应用程序启用脚本功能的关键元素。它提供了简单的接口来包含脚本引擎，如VBScript或JScript。所有其他可用的对象都依靠ScriptControl对象的示例。ScriptControl对象可以使用下面三种不同的方法实例化：</p>
<p style="margin-left: 37.45pt">
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 前期绑定，在表单上进行(使用Components对话框添加)<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 前期绑定，通过代码完成(使用Reference对话框进行)<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 后期绑定(任何时候都可以进行)</p>
<p>
	声明的语法<br />
	声明一个ScriptControl对象的前期绑定变量使用的是VB 6的语法(这也是后期绑定比较常用的语法)。<br />
	Dim|Private|Public [WithEvents] objSC As [MSScriptControl.]ScriptControl</p>
<p>
	下面的语法声明了一个ScriptControl对象的后期绑定变量。后期绑定变量不能处理事件。如果使用后期绑定变量，就不需要在项目中引用脚本控件。<br />
	Dim|Private|Public objSC [As Object|Variant]</p>
<p>
	属性<br />
	ScriptControl对象的属性描述如表21<strong>-</strong>1所示。</p>
<p>
	表21<strong>-</strong>1</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97.5%" width="97%">
	<tbody>
		<tr>
			<td style="width: 72px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 99px">
				<p>
					输入值/返回值</p>
			</td>
			<td style="width: 82px">
				<p>
					访 问 方 式</p>
			</td>
			<td style="width: 296px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 72px">
				<p>
					AllowUI</p>
			</td>
			<td style="width: 99px">
				<p>
					Boolean</p>
			</td>
			<td style="width: 82px">
				<p>
					读/写</p>
			</td>
			<td style="width: 296px">
				<p>
					设置或返回一个值，表示是否显示像MsgBox或InputBox这样的可视化元素。如果该属性被设置为False，那么与界面进行可视化交互的唯一方法就是直接通过主应用程序进行</p>
			</td>
		</tr>
		<tr>
			<td style="width: 72px">
				<p>
					Error</p>
			</td>
			<td style="width: 99px">
				<p>
					Error对象</p>
			</td>
			<td style="width: 82px">
				<p>
					只读</p>
			</td>
			<td style="width: 296px">
				<p>
					返回ScriptControl实例的Error对象的引用</p>
			</td>
		</tr>
		<tr>
			<td style="width: 72px">
				<p>
					Language</p>
			</td>
			<td style="width: 99px">
				<p>
					String</p>
			</td>
			<td style="width: 82px">
				<p>
					读/写</p>
			</td>
			<td style="width: 296px">
				<p>
					设置或返回ScriptControl对象所使用的脚本语言的名称。&ldquo;VBScript&rdquo;和&ldquo;JScript&rdquo;都是本来就支持的语言。如果安装了其他兼容的脚本语言，就可以使用这些脚本语言的名称。设置这个属性会重置ScriptControl对象及其子对象的所有其它成员</p>
			</td>
		</tr>
		<tr>
			<td style="width: 72px">
				<p>
					Modules</p>
			</td>
			<td style="width: 99px">
				<p>
					Modules对象</p>
			</td>
			<td style="width: 82px">
				<p>
					只读</p>
			</td>
			<td style="width: 296px">
				<p>
					返回ScriptControl对象的Modules集合的引用</p>
			</td>
		</tr>
		<tr>
			<td style="width: 72px">
				<p>
					Name</p>
			</td>
			<td style="width: 99px">
				<p>
					String</p>
			</td>
			<td style="width: 82px">
				<p>
					只读</p>
			</td>
			<td style="width: 296px">
				<p>
					如果ScriptControl对象附加到一个表单，该属性就返回控件属性页上为其指定的名称</p>
			</td>
		</tr>
		<tr>
			<td style="width: 72px">
				<p>
					Procedure</p>
			</td>
			<td style="width: 99px">
				<p>
					Procedure对象</p>
			</td>
			<td style="width: 82px">
				<p>
					只读</p>
			</td>
			<td style="width: 296px">
				<p>
					返回默认的&ldquo;Global&rdquo;模块的Procedure集合的引用。要访问其它模块的Procedure集合，可以通过Modules集合直接访问该模块，然后使用Module.Procedure属性</p>
			</td>
		</tr>
		<tr>
			<td style="width: 72px">
				<p>
					SitehWnd</p>
			</td>
			<td style="width: 99px">
				<p>
					Long</p>
			</td>
			<td style="width: 82px">
				<p>
					读/写</p>
			</td>
			<td style="width: 296px">
				<p>
					设置或返回用于执行代码的父窗口的&ldquo;句柄&rdquo;。当脚本控件被用作ActiveX控件时，它会被放到表单上，那么SitehWnd的默认值就是控件的容器的hWnd，否则，如果脚本控件被用作一个对象(不附加到表单)，SitehWnd就是0，这个值对应的是桌面。这个属性会影响到哪个窗口(或控件)具有对脚本控制的UI元素的UI控制权。修改这个属性可以使脚本控件依赖一个具体的窗口，而不是像在某些情况下那样只依赖于桌面(例如，可能想让脚本控件冻结一部分应用程序，而不是桌面)。需要修改这一属性的场合并不多</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<p align="right">
	(续表)&nbsp;&nbsp;</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 94px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 92px">
				<p>
					输入值/返回值</p>
			</td>
			<td style="width: 81px">
				<p>
					访 问 方 式</p>
			</td>
			<td style="width: 279px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 94px">
				<p>
					State</p>
			</td>
			<td style="width: 92px">
				<p>
					Long(States)</p>
			</td>
			<td style="width: 81px">
				<p>
					读/写</p>
			</td>
			<td style="width: 279px">
				<p>
					设置或返回ScriptControl对象的模式，使用States枚举常量。如果这个值被设置为Connected(1)，那么ScriptControl对象就能够接收通过AddObject方法添加的对象所产生的事件。这样，对状态的更改使您能够控制对事件的处理过程</p>
			</td>
		</tr>
		<tr>
			<td style="width: 94px">
				<p>
					TimeOut</p>
			</td>
			<td style="width: 92px">
				<p>
					Long</p>
			</td>
			<td style="width: 81px">
				<p>
					读/写</p>
			</td>
			<td style="width: 279px">
				<p>
					设置或返回一个数字，代表以毫秒为单位的时间，表示ScriptControl对象在终止长时间运行的脚本之前需要等待的时间长度。这个属性可以被设置为常量NoTimeout(<strong>-</strong>1)，这样脚本代码的执行就没有时间限制；但是关闭超时机制是比较危险的，因为可能会有人创建一个包含死循环的脚本。默认的值是10 000ms(10s)。超时时间过后，会产生一个Timeout事件(这取决于ScriptControl对象是否能处理事件)，同时，如果ScriptControl对象启用了AllowUI属性，就会收到一个对话框警告，允许选择继续执行脚本，否则，脚本将中止执行并产生错误。如果这个属性被设置为0(不推荐这样做)，只要脚本停止发送Windows消息超过100ms，就会立即产生Timeout事件</p>
			</td>
		</tr>
		<tr>
			<td style="width: 94px">
				<p>
					UseSafeSubset</p>
			</td>
			<td style="width: 92px">
				<p>
					Boolean</p>
			</td>
			<td style="width: 81px">
				<p>
					读/写</p>
			</td>
			<td style="width: 279px">
				<p>
					设置或返回一个Boolean值，表示脚本控件是否可以运行未被标记为&ldquo;脚本安全&rdquo;的组件。例如，一个脚本可能会试图使用脚本运行时对象FileSystemObject，而这不是一个&ldquo;脚本安全&rdquo;的对象，因为它允许访问文件系统。如果担心脚本可能在客户端机器上进行危险活动，就可以将这个属性设置为True。如果在要求组件必须是&ldquo;脚本安全&rdquo;的宿主(如Internet Explorer)上使用脚本控件，这个属性默认就为True，并且是只读的</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<p>
	方法</p>
<p>
	ScriptControl对象的方法描述如表21<strong>-</strong>2所示。</p>
<p>
	表21<strong>-</strong>2</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 109px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 156px">
				<p>
					参&nbsp;&nbsp;&nbsp; 数</p>
			</td>
			<td style="width: 79px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 202px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					AddCode</p>
			</td>
			<td style="width: 156px">
				<p>
					code：字符串值，表示一个合法的脚本</p>
			</td>
			<td style="width: 79px">
				<p>
					无</p>
			</td>
			<td style="width: 202px">
				<p>
					这是向脚本控件添加脚本的主要方法。在ScriptControl对象上调用该方法时，会在默认的&ldquo;Global&rdquo;模块中自动添加新的代码。在单独的Module对象上调用该方法时，会在具体涉及的模块中添加代码。添加整个过程的代码或一个代码块时，必须在一次调用AddCode方法时添加所有的代码。代码块中的语句之间可以使用冒号(:)隔开，或使用换行符vbNewLine(推荐使用)、vbCr、vbLf和vbCrLf</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					AddObject</p>
			</td>
			<td style="width: 156px">
				<p>
					Name：要添加对象的唯一的字符串名称</p>
				<p>
					object：应用程序范围内的任意对象</p>
				<p>
					addmembers：可选的布尔值，表示对象的公有成员是否能够被ScriptControl对象及其脚本访问</p>
			</td>
			<td style="width: 79px">
				<p>
					无</p>
			</td>
			<td style="width: 202px">
				<p>
					允许脚本访问宿主的运行时对象模型，因为本方法添加的对象将暴露这些对象。添加到ScriptControl的对象在ScriptControl中是全局可访问的。可选的addmembers参数表示已添加对象的成员是否也可以在脚本内部访问</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					Eval</p>
			</td>
			<td style="width: 156px">
				<p>
					Expression：一个字符串值，代表一个合法的&ldquo;表达式&rdquo;，表示被编译或执行的脚本片段</p>
			</td>
			<td style="width: 79px">
				<p>
					表达式的输出(如果有的话)</p>
			</td>
			<td style="width: 202px">
				<p>
					计算一个表达式的值。与VBScript中的Eval函数类似。这是计算您提供的动态表达式最好的方法。如果拿Eval和ExecuteStatement方法相比较，会发现&ldquo;=&rdquo;操作符在使用Eval时被认为是比较操作符，而在使用ExecuteStatement方法时被认为是赋值操作符。因此，x=y在使用Eval时得到的是布尔值，而使用ExecuteStatement方法时，y的值将被赋给x，而没有返回值。被计算的表达式可以利用Module或ScriptControl对象范围内的任何成员</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<p align="right">
	(续表)&nbsp;&nbsp;</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 109px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 146px">
				<p>
					参&nbsp;&nbsp;&nbsp; 数</p>
			</td>
			<td style="width: 90px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 201px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					ExecuteStatement</p>
			</td>
			<td style="width: 146px">
				<p>
					statement：字符串值，表示要执行的语句</p>
			</td>
			<td style="width: 90px">
				<p>
					无</p>
			</td>
			<td style="width: 201px">
				<p>
					与Eval方法不同，ExecuteStatement只执行一个语句，不返回任何值。如果拿Eval和ExecuteStatement方法相比较，会发现&ldquo;=&rdquo;操作符在使用Eval时被认为是比较操作符，而在使用ExecuteStatement方法时被认为是赋值操作符。因此，x=y在使用Eval时得到的是布尔值，而使用ExecuteStatement方法时，y的值将被赋给x，而没有返回值。被计算的表达式可以利用Module或ScriptControl对象范围内的任何成员。要获取一个过程的返回值，应该使用Eval或Run方法</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					Reset</p>
			</td>
			<td style="width: 146px">
				<p>
					无</p>
			</td>
			<td style="width: 90px">
				<p>
					无</p>
			</td>
			<td style="width: 201px">
				<p>
					丢弃ScriptControl对象的所有成员和子对象，将它们初始化为默认状态。调用Reset方法时，State属性被设置为Initialized(0)</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					Run</p>
			</td>
			<td style="width: 146px">
				<p>
					procedurename：要运行的过程或函数的字符串名称</p>
				<p>
					paramarray()：可选的参数数组，其中包括过程或函数所接受的参数值</p>
			</td>
			<td style="width: 90px">
				<p>
					如果调用函数，就返回该函数的返回值</p>
			</td>
			<td style="width: 201px">
				<p>
					在ScriptControl对象上调用Run()时，该方法将试图运行&ldquo;Global&rdquo;模块中具有给定名称的过程或函数。在一个Module对象上调用Run()时，该方法试图运行模块内具有给定名称的过程或函数。也可以使用CodeObject属性直接调用过程和函数</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<p>
	事件</p>
<p>
	ScriptControl对象的事件描述如表21<strong>-</strong>3所示。</p>
<p>
	表21<strong>-</strong>3</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 111px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 133px">
				<p>
					参&nbsp;&nbsp;&nbsp; 数</p>
			</td>
			<td style="width: 301px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 111px">
				<p>
					Error</p>
			</td>
			<td style="width: 133px">
				<p>
					无</p>
			</td>
			<td style="width: 301px">
				<p>
					ScriptControl对象遇到脚本运行错误时会发生该事件。要接收这个事件的通知，必须声明ScriptControl对象的&ldquo;前期绑定&rdquo;变量，并使用WithEvents关键字</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<p align="right">
	(续表)&nbsp;&nbsp;</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 111px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 152px">
				<p>
					参&nbsp;&nbsp;&nbsp; 数</p>
			</td>
			<td style="width: 283px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 111px">
				<p>
					Timeout</p>
			</td>
			<td style="width: 152px">
				<p>
					无</p>
			</td>
			<td style="width: 283px">
				<p>
					脚本执行时间超过Timeout属性的值时，或您决定停止脚本执行时发生该事件。如果有多个ScriptControl对象，那么只有在第一个ScriptControl对象超时时才会发生Timeout事件</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	示例</p>
<p>
	下面这行代码显示了如何实例化一个新的前期绑定脚本控件变量。</p>
<p class="code">
	Set objSC = New [MSScriptControl.]ScriptControl</p>
<p>
	下面这行代码显示了如何实例化一个新的后期绑定脚本控件变量。</p>
<p class="code">
	Set objSC = CreateObject(&quot;[MSScriptControl.]ScriptControl&quot;)</p>
<p>
	下面的脚本片段显示了如何使用AddCode方法添加某过程或函数之外的变量和过程的步骤。整个过程或函数都应该在一次调用之内就添加完毕。</p>
<p class="code">
	strCode = &quot;Option Explicit&quot; &amp; vbNewLine &amp; vbNewLine<br />
	objSC.AddCode strCode<br />
	strCode = &quot;Dim x, y&quot; &amp; vbNewLine &amp; vbNewLine<br />
	objSC.AddCode strCode<br />
	strCode = &quot;x = 15&quot; &amp; vbNewLine &amp; &quot;y = 2&quot;<br />
	objSC.AddCode strCode<br />
	strCode = &quot;Function MultiplyXY(): MultiplyXY = x * y : End Function&quot;<br />
	objSC.AddCode strCode</p>
<p>
	Eval函数允许在运行时执行代码片段。Eval简单且高效，能够实现VB中几乎所有的任务。</p>
<p class="code">
	MsgBox objSC.Eval(InputBox$( _<br />
	&quot;Enter Numeric Expression&quot;, _<br />
	&quot;Eval Example&quot;, &quot;5 * 3 <strong>-</strong> 1&quot;))</p>
<p>
	基于过程的类型，可以以不同方式调用Run方法，这取决于返回值和参数的情况。</p>
<p class="code">
	strCode = &quot;Sub TwoArg(a,b): MsgBox CInt(a + b)&quot; &amp; &quot; : End Sub&quot;<br />
	objSC.AddCode strCode<br />
	objSC.Run &quot;TwoArg&quot;, 1, 2<br />
	strCode = &quot;Function ManyArg(a,b,c,d): ManyArg = a * b + c <strong>-</strong> d&quot;<br />
	strCode = strCode &amp; &quot;: End Function&quot;<br />
	objSC.AddCode strCode<br />
	lngResult = objSC.Run(&quot;ManyArg&quot;, 1, 2, 3, 4)</p>
<p>
	下面的脚本片段演示了Error事件的使用：</p>
<p class="code">
	Private WithEvents objSC As ScriptControl<br />
	<br />
	Private Sub Main()<br />
	Set objSC = New ScriptControl<br />
	...<br />
	objSC.Run &quot;MyProc&quot;<br />
	End Sub<br />
	<br />
	Private Sub objSC_Error<br />
	MsgBox &quot;Script error occurred:&quot; &amp; vbNewLine &amp; _<br />
	&quot;Number: &quot; &amp; objSC.Error.Number &amp; vbNewLine &amp; _<br />
	&quot;Description: &quot; &amp; objSC.Error.Description &amp; vbNewLine &amp; _<br />
	&quot;Line: &quot; &amp; objSC.Error.Line &amp; vbNewLine &amp; _<br />
	&quot;Column: &quot; &amp; objSC.Error.Column &amp; vbNewLine &amp; _<br />
	&quot;Script Text: &quot; &amp; objSC.Error.Text<br />
	End Sub</p>
<p>
	下面的脚本片段演示了Timeout事件的使用：</p>
<p class="code">
	Private WithEvents objSC As ScriptControl<br />
	<br />
	Private Sub Main()<br />
	Set objSC = New ScriptControl<br />
	...<br />
	objSC.Timeout = 10000<br />
	objSC.Run &quot;MyProc&quot;<br />
	End Sub<br />
	<br />
	Private Sub objSC_TimeOut<br />
	MsgBox &quot;The script has timed out.&quot;<br />
	End Sub</p>
<h4>
	2. Module对象</h4>
<p>
	Module对象是Modules集合(在本章前面的内容中曾经介绍过)中的一个成员，它包含脚本中使用的过程、类型和数据声明。脚本控件有一个默认的Global模块，它是自动被使用的，除非存在对已添加的其他模块的具体的成员调用。可以使用AddCode方法向Module对象中添加代码。另一方面，单独的Module对象是使用Modules集合的Add方法来添加的。因为每个模块中的代码都是在模块范围内私有的，所以各个模块可以使用重复的变量和模块名称。如果有很多类似的脚本，每个模块中有些许不同，这种机制就是很有用的。</p>
<p>
	声明语法</p>
<p>
	下面是声明Module对象的一个变量的语法。</p>
<p>
	Dim|Private|Public objModule [As [MSScriptControl.]Module|Object]</p>
<p>
	属性</p>
<p>
	Module对象的属性描述如表21<strong>-</strong>4所示。</p>
<p>
	表21<strong>-</strong>4</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 86px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 106px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 106px">
				<p>
					访 问 方 式</p>
			</td>
			<td style="width: 247px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 86px">
				<p>
					CodeObject</p>
			</td>
			<td style="width: 106px">
				<p>
					对象</p>
			</td>
			<td style="width: 106px">
				<p>
					只读</p>
			</td>
			<td style="width: 247px">
				<p>
					返回一个可以用于调用一个Module对象的公有过程和函数的对象。这是一个后期绑定对象，但它的作用在于允许在脚本中直接调用过程，而无需使用Run方法。模块中的过程或函数将作为对象的公有方法被该属性返回</p>
			</td>
		</tr>
		<tr>
			<td style="width: 86px">
				<p>
					Name</p>
			</td>
			<td style="width: 106px">
				<p>
					字符串</p>
			</td>
			<td style="width: 106px">
				<p>
					读/写</p>
			</td>
			<td style="width: 247px">
				<p>
					Module对象的逻辑名称。也可以用作其在Modules集合中的索引，所以它在该集合中必须是唯一的。如果在集合中添加了一个名字相同的Module对象，新的对象就会覆盖旧的对象</p>
			</td>
		</tr>
		<tr>
			<td style="width: 86px">
				<p>
					Procedure</p>
			</td>
			<td style="width: 106px">
				<p>
					Procedures对象</p>
			</td>
			<td style="width: 106px">
				<p>
					只读</p>
			</td>
			<td style="width: 247px">
				<p>
					返回Module对象的Procedures集合的引用</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	方法</p>
<p>
	Module对象的方法描述如表21<strong>-</strong>5所示。</p>
<p>
	表21<strong>-</strong>5</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97.22%" width="97%">
	<tbody>
		<tr>
			<td style="width: 95px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 123px">
				<p>
					参&nbsp;&nbsp; 数</p>
			</td>
			<td style="width: 145px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 184px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 95px">
				<p>
					Eval</p>
			</td>
			<td style="width: 123px">
				<p>
					it expression：一个字符串值，代表一个合法的&ldquo;表达式&rdquo;，表示被编译或执行的脚本片段</p>
			</td>
			<td style="width: 145px">
				<p>
					表达式的输出(如果有的话)</p>
			</td>
			<td style="width: 184px">
				<p>
					计算一个表达式的值。与VBScript中的Eval函数类似。这是计算您提供的动态表达式最好的方法。如果拿Eval和ExecuteStatement方法相比较，会发现&ldquo;=&rdquo;操作符在使用Eval时被认为是比较操作符，而在使用ExecuteStatement方法时被认为是赋值操作符。因此，x=y在使用Eval时得到的是布尔值，而使用ExecuteStatement方法时，y的值将被赋给x，而没有返回值。Eval方法可以应用于ScriptControl对象和Module对象，并利用其所有成员</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p align="right">
	(续表)&nbsp;&nbsp;</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97.22%" width="97%">
	<tbody>
		<tr>
			<td style="width: 109px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 115px">
				<p>
					参&nbsp;&nbsp; 数</p>
			</td>
			<td style="width: 81px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 242px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					AddCode</p>
			</td>
			<td style="width: 115px">
				<p>
					code：字符串值，表示一个合法的脚本</p>
			</td>
			<td style="width: 81px">
				<p>
					无</p>
			</td>
			<td style="width: 242px">
				<p>
					这是向脚本控件添加脚本的主要方法。在ScriptControl对象上调用该方法时，会在默认的&ldquo;Global&rdquo;模块中自动添加新的代码。在单独的Module对象上调用该方法时，会在具体涉及的模块中添加代码。添加整个过程的代码或一个代码块时，必须在一次调用AddCode方法时添加所有的代码。代码块中的语句之间可以使用冒号(:)隔开，或使用换行符vbNewLine(推荐使用)、vbCr、vbLf和vbCrLf</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					ExecuteStatement</p>
			</td>
			<td style="width: 115px">
				<p>
					statement：字符串值，表示要执行的语句</p>
			</td>
			<td style="width: 81px">
				<p>
					无</p>
			</td>
			<td style="width: 242px">
				<p>
					与Eval方法不同，ExecuteStatement只执行一个语句，不返回任何值。如果拿Eval和ExecuteStatement方法相比较，会发现&ldquo;=&rdquo;操作符在使用Eval时被认为是比较操作符，而在使用ExecuteStatement方法时被认为是赋值操作符。因此，x=y在使用Eval时得到的是布尔值，而使用ExecuteStatement方法时，y的值将被赋给x，而没有返回值。被计算的表达式可以利用Module或ScriptControl对象范围内的任何成员。要获取一个过程的返回值，应该使用Eval或Run方法</p>
			</td>
		</tr>
		<tr>
			<td style="width: 109px">
				<p>
					Run</p>
			</td>
			<td style="width: 115px">
				<p>
					procedurename：要运行的过程或函数的字符串名称</p>
				<p>
					paramarray()：可选的参数数组，其中包括过程或函数所接受的参数值</p>
			</td>
			<td style="width: 81px">
				<p>
					如果调用函数，就返回该函数的返回值</p>
			</td>
			<td style="width: 242px">
				<p>
					在ScriptControl对象上调用Run()时，该方法将运行&ldquo;Global&rdquo;模块中具有给定名称的过程或函数。在一个Module对象上调用Run()时，该方法运行模块内具有给定名称的过程或函数。也可以使用CodeObject属性直接调用过程和函数</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	示例</p>
<p>
	下面的脚本片段演示了使用Module.Run方法调用模块中包含的一个过程。</p>
<p class="code">
	Set objModule = objSC.Modules.Add(&quot;NewModule&quot;)<br />
	objModule.AddCode &quot;Sub Test(): &quot; &amp; _<br />
	vbNewLine &amp; vbTab &amp; &quot;MsgBox &quot;&quot;Hello, world.&quot;&quot;&quot; &amp; _<br />
	vbNewLine &amp; &quot;End Sub&quot;<br />
	objModule.Run &quot;Test&quot;</p>
<p>
	下面的脚本片段演示了使用Module.CodeObject方法调用模块中的代码。我们可以看到，按照这种方法调用过程是很自然的，并且相对于使用ScriptControl.Run方法来说，可能具有更强的可读性，这是因为过程被暴露为CodeObject对象的方法。</p>
<p class="code">
	Set objModule = objSC.Modules.Add(&quot;TestMod&quot;)<br />
	objModule.AddCode &quot;Sub TestProc(): &quot; &amp; _<br />
	vbNewLine &amp; vbTab &amp; &quot;MsgBox &quot;&quot;Hello, world.&quot;&quot;&quot; &amp; _<br />
	vbNewLine &amp; &quot;End Sub&quot;<br />
	objModule.AddCode &quot;Function TestFunction(a) : &amp; _<br />
	vbNewLine &amp; vbTab &amp; &quot;TestFunction = a * a &quot; &amp; _<br />
	vbNewLine &amp; &quot;End Function&quot;<br />
	Set objCodeObject = objModule.CodeObject<br />
	objCodeObject.TestProc<br />
	lngVal = objCodeObject.TestFunction(2)</p>
<p>
	下面的脚本片段显示了添加某过程或函数之外的变量和过程的步骤。整个过程或函数都应该在一次调用之内就添加完毕。</p>
<p class="code">
	strCode = &quot;Option Explicit&quot; &amp; vbNewLine &amp; vbNewLine<br />
	objModule.AddCode strCode<br />
	strCode = &quot;Dim x, y&quot; &amp; vbNewLine &amp; vbNewLine<br />
	objModule.AddCode strCode<br />
	strCode = &quot;x = 15&quot; &amp; vbNewLine &amp; &quot;y = 2&quot;<br />
	objModule.AddCode strCode<br />
	strCode = &quot;Function MultiplyXY(): MultiplyXY = x * y : End Function&quot;<br />
	objModule.AddCode strCode</p>
<p>
	Eval函数允许在运行时执行代码片段。Eval简单且高效，能够实现VB中几乎所有的任务。</p>
<p class="code">
	MsgBox objSC.Eval(InputBox$( _<br />
	&quot;Enter Numeric Expression&quot;, _<br />
	&quot;Eval Example&quot;, &quot;5 * 3 <strong>-</strong> 1&quot;))</p>
<p>
	基于过程的类型，可以以不同方式调用Run方法，这取决于返回值和参数的情况。</p>
<p class="code">
	strCode = &quot;<br />
	Sub TwoArg(a,b): MsgBox CInt(a + b)&quot; &amp; &quot; : End Sub&quot;<br />
	objSC.AddCode strCode<br />
	objSC.Run &quot;TwoArg&quot;, 1, 2<br />
	strCode = &quot;<br />
	Function ManyArg(a,b,c,d): ManyArg = a * b + c <strong>-</strong> d&quot;<br />
	strCode = strCode &amp; &quot;: End Function&quot;<br />
	objSC.AddCode strCode<br />
	lngResult = objSC.Run(&quot;ManyArg&quot;, 1, 2, 3, 4)</p>
<h4>
	3. Modules集合</h4>
<p>
	Modules集合包含一个ScriptControl对象的所有Module对象，包括默认的Global模块。对Global模块的成员的调用可以直接通过ScriptControl对象来进行，而不需要遍历Modules集合。Global对象还具有一个值与常量GlobalModule相等的索引。</p>
<p>
	Module对象可以使用Add方法被添加到Modules集合中。使用默认的Modules.Item方法可以访问具体的Module对象。Count属性提供了集合中Module对象的个数。整个集合可以通过几种方式来遍历，最常用的是使用For Each &hellip; Next循环。因为不能删除单个模块，所以必须使用ScriptControl对象的Reset方法来删除不想要的模块，该方法将清空整个集合。</p>
<p>
	属性</p>
<p>
	Modules集合唯一的属性描述如表21<strong>-</strong>6所示。</p>
<p>
	表21<strong>-</strong>6</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 125px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 165px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 165px">
				<p>
					访 问 方 式</p>
			</td>
			<td style="width: 165px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 125px">
				<p>
					Count</p>
			</td>
			<td style="width: 165px">
				<p>
					Long</p>
			</td>
			<td style="width: 165px">
				<p>
					只读</p>
			</td>
			<td style="width: 165px">
				<p>
					返回Modules集合中Module对象的个数</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	方法</p>
<p>
	Modules集合对象的方法描述如表21<strong>-</strong>7所示。</p>
<p>
	表21<strong>-</strong>7</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 66px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 124px">
				<p>
					参&nbsp;&nbsp;&nbsp; 数</p>
			</td>
			<td style="width: 108px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 247px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 66px">
				<p>
					Add</p>
			</td>
			<td style="width: 124px">
				<p>
					name：字符串值，表示要添加模块的名称；该名称将用作在Modules集合中的索引</p>
				<p>
					module：可选。要被加入集合的Module对象</p>
			</td>
			<td style="width: 108px">
				<p>
					如果省略module参数，就返回新的Module对象</p>
			</td>
			<td style="width: 247px">
				<p>
					使用这个方法可以在Modules集合中添加一个新的Module对象；如果在一个小型的工程中，只包含相对较少的脚本，可能就只需要使用&ldquo;Global&rdquo;模块。但是如果有很多脚本，那么将它们分别组织到各个模块中是很有好处的&mdash;&mdash; 尤其是如果需要在不同的模块中重复使用具有相同名称的过程和函数时，就更应该这样做</p>
			</td>
		</tr>
		<tr>
			<td style="width: 66px">
				<p>
					Item</p>
			</td>
			<td style="width: 124px">
				<p>
					index：一个Long或String类型的值，分别表示一个索引或一个关键字</p>
			</td>
			<td style="width: 108px">
				<p>
					如果存在匹配的index，就返回集合中的一个Module对象</p>
			</td>
			<td style="width: 247px">
				<p>
					这是集合的默认属性，所以很多程序员都会忽略item方法的实际名称：Set objModule = objSC.Modules(&quot;MyModule&quot;)</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	示例</p>
<p>
	下面的代码显示了如何直接访问Global模块。使用同样的语法，不同的模块名，就可以访问其他的模块。</p>
<p class="code">
	Set objModule = sc.Modules(&quot;Global&quot;)</p>
<p>
	下面的脚本片段演示了如何遍历Modules集合：</p>
<p class="code">
	For Each objModule In objSC.Modules<br />
	strModuleList = strModuleList &amp; vbNewLine &amp; objModule.Name<br />
	Next</p>
<p>
	模块允许使用独立的脚本并提供独立的名字空间。下面的脚本片段显示了如何在两个不同的模块中包含同名的脚本：</p>
<p class="code">
	&#39; Add code to separate modules, using same sub names.<br />
	Set objModule = objSC.Modules.Add(&quot;Maine&quot;)<br />
	objModule.AddCode &quot;Sub ShowState&quot; &amp; _<br />
	vbNewLine &amp; vbTab &amp; &quot;MsgBox &quot;&quot;In Maine&quot;&quot;&quot; &amp; _<br />
	vbNewLine &amp; &quot;End Sub&quot;<br />
	Set objModule = Nothing<br />
	Set objModule = objSC.Modules.Add(&quot;Ohio&quot;)<br />
	objModule.AddCode &quot;Sub ShowState&quot; &amp; _<br />
	vbNewLine &amp; vbTab &amp; &quot;MsgBox &quot;&quot;In Ohio&quot;&quot;&quot; &amp; _<br />
	vbNewLine &amp; &quot;End Sub&quot;</p>
<h4>
	4. Procedure对象</h4>
<p>
	Procedure对象定义了代码的一个逻辑单元，在VBScript中可以是一个Sub或一个Function。Procedure对象包含了很多有用的属性，使您能够检查过程名、参数个数以及过程是否具有返回值。脚本代码的入口也是由Procedure对象提供的。</p>
<p>
	声明语法</p>
<p>
	下面是声明Procedure对象的一个变量的语法。</p>
<p>
	Dim|Private|Public objProc [As [MSScriptControl.]Procedure|Object]</p>
<p>
	属性</p>
<p>
	Procedure对象的属性描述如表21<strong>-</strong>8所示。</p>
<p>
	表21<strong>-</strong>8</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 93px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 77px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 86px">
				<p>
					访 问 方 式</p>
			</td>
			<td style="width: 289px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 93px">
				<p>
					hasReturnValue</p>
			</td>
			<td style="width: 77px">
				<p>
					Boolean</p>
			</td>
			<td style="width: 86px">
				<p>
					只读</p>
			</td>
			<td style="width: 289px">
				<p>
					返回过程是否有返回值(换句话说，是一个过程还是一个函数)</p>
			</td>
		</tr>
		<tr>
			<td style="width: 93px">
				<p>
					Name</p>
			</td>
			<td style="width: 77px">
				<p>
					String</p>
			</td>
			<td style="width: 86px">
				<p>
					只读</p>
			</td>
			<td style="width: 289px">
				<p>
					Procedure对象的名称，应该和对象中包含的某个实际的过程或函数名相同。这个名称还用作在Procedures集合的索引。如果使用AddCode方法在模块中添加另一个同名过程，新的过程就会覆盖模块中原来的过程</p>
			</td>
		</tr>
		<tr>
			<td style="width: 93px">
				<p>
					NumArgs</p>
			</td>
			<td style="width: 77px">
				<p>
					Long</p>
			</td>
			<td style="width: 86px">
				<p>
					只读</p>
			</td>
			<td style="width: 289px">
				<p>
					返回Procedure对象中过程或函数接收参数的个数</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	方法</p>
<p>
	Procedure对象的方法描述如表21<strong>-</strong>9所示。</p>
<p>
	表21<strong>-</strong>9</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 71px">
				<p>
					名&nbsp; 称</p>
			</td>
			<td style="width: 128px">
				<p>
					参&nbsp; 数</p>
			</td>
			<td style="width: 116px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 231px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 71px">
				<p>
					Item</p>
			</td>
			<td style="width: 128px">
				<p>
					index：一个Long或String类型的值，分别表示一个索引或一个关键字</p>
			</td>
			<td style="width: 116px">
				<p>
					如果存在匹配的index，就返回集合中的一个Module对象</p>
			</td>
			<td style="width: 231px">
				<p>
					这是集合的默认属性，所以很多程序员都会忽略item方法的实际名称：Set objProc = objMod.Procedure(&quot;MyProc&quot;)</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	注意，Procedures集合没有Add方法，但可以使用AddCode方法给模块添加新的方法，这样就会隐式地创建一个Procedure对象并添加到集合中。</p>
<h4>
	5. Procedures集合</h4>
<p>
	Procedures集合中保存着某一给定的Modules对象的所有过程。它为遍历某一给定模块的所有过程并访问其内部代码提供了一种便捷的途径。每个过程都是使用Module对象的AddCode方法添加到集合中，而不是直接使用集合操作来进行的。同样，某个过程被添加到集合中之后，也无法将其删除，因为Procedures集合没有Remove方法。</p>
<p>
	属性</p>
<p>
	Procedures集合对象唯一的属性描述如表21<strong>-</strong>10所示。</p>
<p>
	表21<strong>-</strong>10</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 125px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 165px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 165px">
				<p>
					访 问 方 式</p>
			</td>
			<td style="width: 165px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 125px">
				<p>
					Count</p>
			</td>
			<td style="width: 165px">
				<p>
					Long</p>
			</td>
			<td style="width: 165px">
				<p>
					只读</p>
			</td>
			<td style="width: 165px">
				<p>
					返回Procedures集合中Procedure对象的个数</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	方法</p>
<p>
	Procedures集合对象没有任何方法。</p>
<p>
	示例</p>
<p>
	下面的脚本片段使用For Each &hellip; Next循环语法遍历Procedures集合：</p>
<p class="code">
	For Each objProcedure In objModule.Procedures<br />
	strList = strList &amp; &quot;Name: &quot; &amp; objProcedure.Name<br />
	strList = strList &amp; vbNewLine &amp; vbTab<br />
	strList = strList &amp; &quot;Argument Count: &quot; &amp; objProcedure.NumArgs<br />
	strList = strList &amp; vbNewLine &amp; vbTab<br />
	strList = strList &amp; &quot;Has Return: &quot; &amp; objProcedure.HasReturnValue<br />
	strList = strList &amp; vbNewLine &amp; vbNewLine<br />
	Next</p>
<h4>
	6. Error对象</h4>
<p>
	Error对象提供与脚本控件相关联的语法和运行时错误信息。虽然Error对象提供的信息和VB、VBScript中Err对象提供的信息类似，但在诊断脚本相关的问题时，有一些很有价值的额外属性(Column、Text、Line)。虽然在VB中也能够声明和初始化Error对象，但是一般还是通过ScriptControl对象直接访问Error对象的成员。</p>
<p>
	与Err对象不同，Error对象的作用域不是全局的，它只处理与某个ScriptControl对象实例相关联的错误。Error对象在每次更改ScriptControl.Language属性，或调用ScriptControl对象的Reset、AddCode、Eval、ExecuteStatement或Clear时方法都会被重置。使用Clear方法可以显式地重置Error对象的属性。脚本内部处理的运行时错误不会在应用程序级产生。</p>
<p>
	&ldquo;通过脚本控制来处理错误&rdquo;这一节提供了关于错误处理策略的详细信息。如果需要对VBScript的错误处理机制有个初步的了解，那么第6章&ldquo;错误处理和调试&rdquo;也是一个很好的参考。</p>
<p>
	属性</p>
<p>
	Error对象的属性描述如表21<strong>-</strong>11所示。</p>
<p>
	表21<strong>-</strong>11</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 116px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 142px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 95px">
				<p>
					访 问 方 式</p>
			</td>
			<td style="width: 192px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 116px">
				<p>
					Column</p>
			</td>
			<td style="width: 142px">
				<p>
					Long</p>
			</td>
			<td style="width: 95px">
				<p>
					只读</p>
			</td>
			<td style="width: 192px">
				<p>
					返回一个列号，表示添加脚本代码时发生的语法错误的位置</p>
			</td>
		</tr>
		<tr>
			<td style="width: 116px">
				<p>
					Description</p>
			</td>
			<td style="width: 142px">
				<p>
					String</p>
			</td>
			<td style="width: 95px">
				<p>
					只读</p>
			</td>
			<td style="width: 192px">
				<p>
					返回脚本错误的描述信息</p>
			</td>
		</tr>
		<tr>
			<td style="width: 116px">
				<p>
					HelpContext</p>
			</td>
			<td style="width: 142px">
				<p>
					Long</p>
			</td>
			<td style="width: 95px">
				<p>
					只读</p>
			</td>
			<td style="width: 192px">
				<p>
					如果错误发生的脚本有可用的帮助文件(可能性不大)，这个属性就返回帮助文件中包含错误信息的部分的标识</p>
			</td>
		</tr>
		<tr>
			<td style="width: 116px">
				<p>
					HelpFile</p>
			</td>
			<td style="width: 142px">
				<p>
					String</p>
			</td>
			<td style="width: 95px">
				<p>
					只读</p>
			</td>
			<td style="width: 192px">
				<p>
					如果错误发生的脚本有可用的帮助文件(可能性不大)，这个属性就返回帮助文件的名称</p>
			</td>
		</tr>
		<tr>
			<td style="width: 116px">
				<p>
					Line</p>
			</td>
			<td style="width: 142px">
				<p>
					Long</p>
			</td>
			<td style="width: 95px">
				<p>
					只读</p>
			</td>
			<td style="width: 192px">
				<p>
					返回一个行号，表示添加脚本代码时发生的语法错误的位置</p>
			</td>
		</tr>
		<tr>
			<td style="width: 116px">
				<p>
					Number</p>
			</td>
			<td style="width: 142px">
				<p>
					Long</p>
			</td>
			<td style="width: 95px">
				<p>
					只读</p>
			</td>
			<td style="width: 192px">
				<p>
					返回脚本错误的错误号</p>
			</td>
		</tr>
		<tr>
			<td style="width: 116px">
				<p>
					Source</p>
			</td>
			<td style="width: 142px">
				<p>
					String</p>
			</td>
			<td style="width: 95px">
				<p>
					只读</p>
			</td>
			<td style="width: 192px">
				<p>
					返回脚本错误产生的源文件名</p>
			</td>
		</tr>
		<tr>
			<td style="width: 116px">
				<p>
					Text</p>
			</td>
			<td style="width: 142px">
				<p>
					String</p>
			</td>
			<td style="width: 95px">
				<p>
					只读</p>
			</td>
			<td style="width: 192px">
				<p>
					返回一个字符串，包含产生语法错误的那一小段代码。如果允许在应用程序中添加或编辑脚本，就可以使用这个属性再加上Description、Line和Column帮助您了解如何改正语法错误。在调试脚本时也可以使用这个属性</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	方法</p>
<p>
	Error对象唯一的方法描述如表21<strong>-</strong>12所示。</p>
<p>
	表21<strong>-</strong>12</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 105px">
				<p>
					名&nbsp;&nbsp;&nbsp; 称</p>
			</td>
			<td style="width: 134px">
				<p>
					参&nbsp;&nbsp;&nbsp; 数</p>
			</td>
			<td style="width: 90px">
				<p>
					返&nbsp; 回&nbsp; 值</p>
			</td>
			<td style="width: 216px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 105px">
				<p>
					Clear</p>
			</td>
			<td style="width: 134px">
				<p>
					无</p>
			</td>
			<td style="width: 90px">
				<p>
					无</p>
			</td>
			<td style="width: 216px">
				<p>
					重置Error对象的所有属性。这个方法是在ScriptControl.Language属性发生变化或调用Reset、AddCode、Eval、ExecuteStatement方法时隐式调用的</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<h3>
	<strong>21.4</strong>.3&nbsp; 常量</h3>
<p>
	下面的具名常量和枚举常量可以在引用脚本控件的工程中使用。这些常量在引用脚本控件的Visual Basic应用程序中是全局可访问的。对于每个常量，这一节都将介绍其类型、值和使用的场合。</p>
<h4>
	1. GlobalModule具名常量</h4>
<p>
	类型：String<br />
	值：&ldquo;Global&rdquo;</p>
<p>
	通过使用支持多个模块的脚本引擎(如VBScript或JScript)使用脚本控件时，可以使用GlobalModule常量访问ScriptControl.Modules集合中默认的Global模块。</p>
<h4>
	2. NoTimeout具名常量</h4>
<p>
	类型：Long<br />
	值：&ndash;1</p>
<p>
	这个常量可以用于设置ScriptControl对象的Timeout属性，防止脚本执行超时。更多细节请参看ScriptControl.Tiemout属性(本章前面的内容中曾经讨论过)。</p>
<h4>
	3. ScriptControlState枚举常量</h4>
<p>
	这个枚举常量是和ScriptControl.State属性一起使用的。State属性的目的在于控制AddObject加入到ScriptControl中的对象的事件产生。默认值Initialized(0)表示ScriptControl不会响应这些对象产生的事件。其他可能的值，如Connected(1)表示ScriptControl会响应发生的事件。</p>
<h3>
	21.5&nbsp; 脚本控件错误处理</h3>
<p>
	错误处理不容忽视，尤其是在处理来自多处的代码时。对于动态生成的脚本，和您输入的表达式更是这样。要处理错误，就必须同时使用VB的Err对象和脚本控件的Error对象。如果运行脚本控件的多个实例，那么每个实例都有一个独立的Error对象。发生错误时，如果有适当的策略来处理错误，通常就会清楚这个错误并继续执行程序。在脚本(尤其是从文件中加载的脚本)中应尽量使用所有可能的错误处理技术，并尽可能在内部完成处理。</p>
<p>
	根据VB的设置情况，错误处理程序在调试模式(在集成开发环境的General Options标签页中勾选Break on Unhandled Errors)下可能无法正常工作。此外，脚本中的错误处理程序将依赖于Internet Explorer中Disable Script Debugging选项的设置，以及调试器的使用。脚本错误会自动调用调试器，绕过错误处理代码。参看第6章可以获得关于脚本调试的更多信息。</p>
<p>
	在.NET中，未处理的错误会作为异常传播到.NET层，异常可以被捕捉到，并使用标准的.NET错误处理机制，如Try &hellip; Catch块来处理。</p>
<p>
	脚本控件在设置全局属性时可能产生的几类错误如表21-13所示。</p>
<p>
	表21-13</p>
<p>
	&nbsp;</p>
<p>
	&nbsp;</p>
<table align="center" border="1" cellpadding="0" cellspacing="0" style="width: 97%" width="97%">
	<tbody>
		<tr>
			<td style="width: 222px">
				<p>
					错&nbsp;&nbsp;&nbsp; 误</p>
			</td>
			<td style="width: 324px">
				<p>
					描&nbsp;&nbsp;&nbsp; 述</p>
			</td>
		</tr>
		<tr>
			<td style="width: 222px">
				<p>
					脚本仍在运行，但无法继续执行</p>
			</td>
			<td style="width: 324px">
				<p>
					在脚本运行时试图修改ScriptControl对象的某个成员</p>
			</td>
		</tr>
		<tr>
			<td style="width: 222px">
				<p>
					不能设置UseSafeSubset属性</p>
			</td>
			<td style="width: 324px">
				<p>
					包含脚本控件的应用程序强制进入安全模式</p>
			</td>
		</tr>
		<tr>
			<td style="width: 222px">
				<p>
					脚本执行超时</p>
			</td>
			<td style="width: 324px">
				<p>
					脚本执行时间超过了Timeout属性设置的值而停止</p>
			</td>
		</tr>
		<tr>
			<td style="width: 222px">
				<p>
					未设置语言属性</p>
			</td>
			<td style="width: 324px">
				<p>
					某些属性只能在设置了Language属性之后才能设置</p>
			</td>
		</tr>
		<tr>
			<td style="width: 222px">
				<p>
					选定的脚本引擎不支持某成员</p>
			</td>
			<td style="width: 324px">
				<p>
					使用除VBScript和JScript之外的语言是时，并不支持所有的属性和方法</p>
			</td>
		</tr>
		<tr>
			<td style="width: 222px">
				<p>
					对象不再合法</p>
			</td>
			<td style="width: 324px">
				<p>
					重置脚本控件时(调用Reset方法或修改Language属性时会导致重置)，对象已经先被释放了</p>
			</td>
		</tr>
	</tbody>
</table>
<p>
	&nbsp;</p>
<div style="clear: both">
	&nbsp;</div>
<p>
	这些错误一般都可以通过仔细的编程来避免，对于错误处理策略来说并不是什么大问题。只有在下述两种情况下错误才会真正带来麻烦，首先是向脚本控件添加脚本代码时(脚本中存在语法错误)，其次是当执行这部分脚本代码时(脚本中存在运行时错误)。错误发生时，可能需要同时检查Err和Error对象。但是，脚本控件的Error对象提供了关于错误本质的额外信息。下面的示例显示了VB中假想的一个错误处理过程。</p>
<p class="code">
	Dim strCode As String<br />
	Dim strValue As String<br />
	sc.Reset<br />
	On Error GoTo SyntaxErrorHandler<br />
	strCode = InputBox(&quot;Enter Function (name it Test(a))&quot;, _<br />
	&quot;Syntax Error Testing&quot;, _<br />
	&quot;Sub Test(a): MsgBox &quot;&quot;Result: &quot;&quot; &amp; CStr(a*a): End Sub&quot;)<br />
	sc.AddCode strCode<br />
	On Error GoTo RuntimeErrorHandler<br />
	strValue = InputBox(&quot;Enter a Value for Test function&quot;, _<br />
	&quot;Runtime Error Testing&quot;, _<br />
	&quot;test&quot;)<br />
	sc.Run &quot;Test&quot;, strValue<br />
	Exit Sub<br />
	SyntaxErrorHandler:<br />
	MsgBox &quot;Error # &quot; &amp; Err.Number &amp; &quot;: &quot; &amp; _<br />
	Err.Description, vbCritical, &quot;Syntax Error in Script&quot;<br />
	Exit Sub<br />
	<br />
	RuntimeErrorHandler:<br />
	MsgBox &quot;Error # &quot; &amp; Err.Number &amp; &quot;: &quot; &amp; _<br />
	Err.Description, vbCritical, &quot;Runtime Error in Script&quot;</p>
<p>
	VB可以以几种方式处理错误：通过使用On Error Goto [Label]和在VBScript中使用On Error Resume Next，并立即检查Err.Number。下面的示例演示了On Error Resume Next及脚本控件Error对象的使用，提供了关于错误处理的更多信息：</p>
<p class="code">
	On Error Resume Next<br />
	sc.AddCode strCode<br />
	If Err Then<br />
	With sc.Error<br />
	MsgBox &quot;Error # &quot; &amp; .Number &amp; &quot;: &quot; _<br />
	&amp; .Description &amp; vbCrLf _<br />
	&amp; &quot;At Line: &quot; &amp; .Line &amp; &quot; Column: &quot; &amp; .Column _<br />
	&amp; &quot; : &quot; &amp; .Text, vbCritical, &quot;Syntax Error&quot;<br />
	End With<br />
	Else<br />
	MsgBox &quot;No Error, result: &quot; &amp; CStr(sc.Run(&quot;Test&quot;, _<br />
	strValue))<br />
	If Err Then<br />
	With sc.Error<br />
	MsgBox &quot;Error # &quot; &amp; .Number &amp; &quot;: &quot; _<br />
	&amp; .Description &amp; vbCrLf _<br />
	&amp; &quot;At Line: &quot; &amp; .Line _<br />
	{}, vbCritical, &quot;Runtime Error&quot;<br />
	End With<br />
	End If<br />
	End If</p>
<p>
	可以使用两个由初始的ScriptControl对象暴露的事件Event和Timeout，来处理某些错误。但是，在某些情况下，比较难以应付，此时应该使用On Error &hellip;语句，因为：</p>
<p style="margin-left: 37.15pt">
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果有多个ScriptControl对象，那么只有第一个ScriptControl对象才会产生Timeout事件。<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ScriptControl对象或者被附加到表单，或者使用WithEvents关键字来初始化，这很可能并不是需要的方式。<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 执行某些可能导致错误的脚本时，会损失一定的处理粒度。</p>
<p>
	如果不想在应用程序中添加任何其他的错误处理脚本代码，就应该使用Error事件，如下面的示例所示：</p>
<p class="code">
	Private Sub sc_Error()<br />
	Dim strMsg As String<br />
	With sc.Error<br />
	strMsg = &quot;Script error has occurred:&quot; &amp; vbCrLf &amp; vbCrLf<br />
	strMsg = strMsg &amp; .Description &amp; vbCrLf<br />
	strMsg = strMsg &amp; &quot;Line # &quot; &amp; .Line<br />
	&#39; Syntax errors have additional properties<br />
	If InStr(.Source, &quot;compilation&quot;) &gt; 0 Then<br />
	strMsg = strMsg &amp; &quot;, Column# &quot; &amp; .Column<br />
	strMsg = strMsg &amp; &quot;, Text: &quot; &amp; .Text<br />
	End If<br />
	strMsg = strMsg &amp; vbCrLf<br />
	End With<br />
	MsgBox strMsg, vbCritical, &quot;Script Error&quot;<br />
	sc.Error.Clear<br />
	End Sub</p>
<p>
	注意使用ScriptControl对象的Error事件时，事件处理程序是在On Error &hellip;代码之前被调用的。因此，同时使用这两种错误处理技术会导致出现两条错误信息，使得每一种方法都无法有效地进行。</p>
<h3>
	21.6&nbsp; 调试</h3>
<p>
	用一句简单的话来描述使用脚本控件调试包含在应用程序的脚本，那就是：可以在VB集成开发环境中调试原有的Visual Basic代码，但是要调试脚本中的代码，就必须使用可以免费下载的Microsoft脚本调试器(Microsoft Script Debugger)。安装了调试器之后，任何未处理的错误或脚本中的Stop语句都将调用该调试器，就像调用其他脚本一样。</p>
<p>
	关于脚本调试期和脚本调试技术的更多细节，请参看第6章&ldquo;错误处理和调试&rdquo;。</p>
<p>
	还要记住的是，如果在脚本执行期间调用调试器，脚本执行时间就会有所增加，但仍然受Timeout属性的限制。换句话说，如果Timeout被设置为10 000ms(10s)，而调试器的使用使脚本的执行暂停了超过10s的时间，那么脚本控件就会弹出超时警告对话框。</p>
<p>
	由于这个原因，在进行调试的时候，可能需要将Timeout属性设置成NoTimeout(-1)，并在发布脚本产品之前在将其设置成另外的值。实现这一点，一个很好的方法是使用具名常量来设置Timeout值，但要使用条件编译标志和#IFDEF语句来控制常量的值，如下：</p>
<p class="code">
	#IFDEF blnDebugging<br />
	Const TIMEOUT_VAL = -1<br />
	#ELSE<br />
	Const TIMEOUT_VAL = 15000<br />
	#ENDIF<br />
	...objSC.Timeout = TIMEOUT_VAL<br />
	...</p>
<h3>
	21.7&nbsp; 使用已编码脚本</h3>
<p>
	脚本控件的确支持已编码脚本(请参看第14章)。但是要记住两点。</p>
<p>
	首先，设置已编码脚本的Langauage属性时，应将其设置为&ldquo;VBScript.Encode&rdquo;，而不是一般的&ldquo;VBSript&rdquo;。</p>
<p>
	其次，如果从文件或数据库中加载一个已编码脚本，就需要使用别的技术来处理已编码脚本中存在特殊字符的情况。对于从文件中加载，可能会需要通过FileSystemObject. OpenTextFile方法(请参看第7章)使用脚本运行时TextStream对象，而不是使用原来的Visual Basic函数来打开文件。对于存储和加载数据库，最好是将脚本作为二进制数据来保存，而不能使用一般的Char或VarChar列保存。</p>
<h3>
	21.8&nbsp; .NET工程范例</h3>
<p>
	范例工程ScriptControlDemo演示了脚本控件在一个.NET环境中的基本工作原理，包括应用程序如何使用脚本和其他技术共享其对象。VB.NET演示工程不代表实际的应用场景，而是用于实践脚本控件的各种特性，演示其在.NET运行时环境中的工作原理，并且在Visual Basic 6或其他支持COM的语言中具有相似的工作原理。</p>
<p>
	可以从www.wrox.com下载这个范例工程以及本书中提到的其他代码。ComplexSC工程包含在一个名为VisualBasic6Demoi.zip的文件中。</p>
<p>
	可以在任何文本编辑器中阅读ScriptControlDemo工程的代码(文件frmMain.vb中包含了所有实际的脚本控件代码)，或者可以在Visual Studio .NET 2005中加载这个工程。该工程实际上是在Visual Basic 2005 Express Edition中创建的。如果没有Visual Studio .NET 2005的完整版本，就可以从Microsoft下载这个开发环境，地址是：</p>
<p>
	http://msdn.microsoft.com/vstudio/express/vb/</p>
<p>
	即使不熟悉VB.NET的使用，但如果熟悉Visual Basic、VBA或VBScript的话，也会觉得VB.NET的语法是比较熟悉的。下面是该工程中的一个代码示例，它演示了如何在控件中添加一段简单的代码并运行：</p>
<p class="code">
	Dim scriptCtl As MSScriptControl.ScriptControl = _<br />
	New MSScriptControl.ScriptControl()<br />
	scriptCtl.Language = &quot;VBScript&quot;<br />
	Dim stringBldr As System.Text.StringBuilder = New System.Text.StringBuilder()<br />
	stringBldr.Append(&quot;Sub ShowMyName(ByVal firstName, ByVal lastName)&quot;)<br />
	stringBldr.Append(vbNewLine)<br />
	stringBldr.Append(&quot; MsgBox(&quot;&quot;My name is &quot;&quot; &amp; firstName &amp; &quot;&quot; &quot;&quot; &amp; lastName)&quot;)<br />
	stringBldr.Append(vbNewLine)<br />
	stringBldr.Append(&quot;End Sub&quot;)<br />
	scriptCtl.AddCode(stringBldr.ToString())<br />
	Dim parms() As Object = {&quot;Super&quot;, &quot;Fly&quot;}<br />
	scriptCtl.AllowUI = True<br />
	scriptCtl.Run(&quot;ShowMyName&quot;, parms)</p>
<h3>
	21.9&nbsp; Visual Basic 6工程范例</h3>
<p>
	范例工程ComplexSC演示了脚本控件的基本工作原理，包括应用程序如何与脚本共享其对象以及传送静态事件&mdash;&mdash; 由于这一需要，该工程是ActiveX EXE类型的。</p>
<p>
	可以从www.wrox.com下载这个范例工程以及本书中提到的其他代码。ComplexSC工程包含在一个名为Chapter 21 downloads.VisualBasic6Demoi.zip的文件中。</p>
<p>
	创建依赖外部数据库的数据库应用程序时，总是会遇到应用程序中输入数据库连接字符串的问题，该字符串将关联适当的数据库和适当的服务器。这部分信息通常是从系统注册表中使用一个关键字检索获取的，它还标识了软件作者和应用程序信息：</p>
<p>
	Sample Registry Path: SOFTWARE\Company Name\App Name\<br />
	Sample Key Name: MyAppConnection</p>
<p>
	这个范例工程提供的方法可以用于创建、存储和编辑诸如连接字符串这样的应用程序设置的注册表信息。ComplexSC工程中的Visual Basic表单和代码都被设计为普通的，可以通过脚本定制的。这意味着可以发布新的脚本，而不需要重编译和重发布整个VB应用程序。</p>
<p>
	图21-2显示了ComplexSC工程的主表单。</p>
<p>
	图21-2</p>
<p>
	这里的可能性是很多的：通过在应用程序中暴露对象，并将某些事件传递给脚本，该脚本就会以宏方式运行以适应需要。有一些很特殊的性质，对于在表单和脚本之间的事件传递来说尤其如此。要实现这一功能，所有的控件都必须在设计时被放置到表单上，其中的一些可能要放在控件数组中。脚本可以很容易地控制所有控件的所有属性和方法，但对于控件数组(可选的连接字符串标签及其值)的使用来说，可以简化表单成员的动态修改。这里根据不同的连接选择(OLE DB、ODBC和DSN)，可以显示与连接相关的不同的标签和可编辑的值。</p>
<p>
	表单成员的共享可以很容易地通过CShared类来实现，这个类允许与脚本共享主表单及其成员(如下面的示例所示)。虽然有时可能需要暴露单个元素，而非整个表单，并阻止脚本操作那些希望保护的元素，但对于这个应用程序来说，不需要考虑这些。</p>
<p class="code">
	Option Explicit<br />
	Private m_Form As Form<br />
	Public Property Get Form() As Object<br />
	Set Form = m_Form<br />
	End Property<br />
	Friend Property Set Form(ByVal newValue As Object)<br />
	Set m_Form = newValue<br />
	End Property</p>
<p>
	下面我们将表单封装在CShared类中。有了CShared类，就需要使用脚本控件的AddObject方法与脚本共享表单。这是通过InitScriptControl过程完成的，该过程是在表单加载时执行的(在Form_Load时间处理程序中调用)。此时要传递一个对VB表单的引用，并通过CShared.Form属性来暴露它。</p>
<p class="code">
	Private Sub Form_Load()<br />
	Set objScript = InitScriptControl(Me)<br />
	objScript.Run &quot;init&quot;<br />
	End Sub</p>
<p>
	下面的InitScriptControl过程实例化ScriptControl对象，加载脚本，实例化CShared对象，并将其暴露给脚本控件。因为将AddObject方法的第三个参数设置为True，所以表单中所有的成员都是共享的。</p>
<p class="code">
	Function InitScriptControl(frmForm As Form) As ScriptControl<br />
	Dim objSC As ScriptControl<br />
	Dim fileName As String, intFnum As Integer<br />
	Dim objShare As New CShared<br />
	&#39; create a new instance of the control<br />
	Set objSC = New ScriptControl<br />
	objSC.Language = &quot;VBScript&quot;<br />
	objSC.AllowUI = True<br />
	Set objShare.Form = frmForm<br />
	objSC.AddObject &quot;share&quot;, objShare, True<br />
	&#39; load the code into the script control<br />
	fileName = App.Path &amp; &quot;regeditor.scp&quot;<br />
	intFnum = FreeFile<br />
	Open fileName For Input As #intFnum<br />
	objSC.AddCode Input$(LOF(intFnum), intFnum)<br />
	Close #intFnum<br />
	&#39; return to the caller<br />
	Set InitScriptControl = objSC<br />
	End Function</p>
<p>
	初始化脚本控件之后，Form_Load代码将调用脚本中的Init过程，该过程将设置表单中所有必需的控件。在实际应用中，有些控件将被预置一些属性(如背景色、是否被启用，等等)，而其他属性是通过脚本访问由CShared.Form方法暴露的表单成员来进行初始化的。</p>
<p class="code">
	Sub Init()<br />
	Dim i, strTmp<br />
	Form.Caption = &quot;Connection Registration Manager&quot;<br />
	strTmp = &quot;This application saves the database connection&quot;<br />
	strTmp = strTMP &amp; &quot; string in the registry. &quot; &amp; vbCrLf<br />
	Form.lblExplanation = strTmp<br />
	Form.lblRegistry.Caption = &quot;&quot;<br />
	&#39; this information should be reflected in your application<br />
	&#39; the standard is to store the registry keys in subhives<br />
	&#39; for different companies and projects<br />
	Form.txtSubpath.Text = &quot;SOFTWARE Company Name App Name &quot;<br />
	&#39; finally the name of the key<br />
	&#39; you could similarly extend this application so it would<br />
	&#39; work like a wizard, and register several keys<br />
	Form.txtKey.Text = &quot;MyAppConnection&quot;<br />
	Form.lblRegistry.Caption = &quot;&quot;<br />
	Form.cmdRegister.Enabled = False<br />
	Form.cmdProcess.Enabled = True<br />
	For i = 0 To 5<br />
	Form.lblLabel(i).Visible = False<br />
	Form.txtText(i).Visible = False<br />
	Next<br />
	Form.cboCombo.Clear<br />
	Form.cboCombo.AddItem &quot;OLE DB&quot;<br />
	Form.cboCombo.AddiTem &quot;ODBC&quot;<br />
	Form.cboCombo.AddItem &quot;DSN&quot;<br />
	End Sub</p>
<p>
	接下来，要响应应用程序产生的事件。在这个简单的例子中，只要将应用程序截获的事件直接传递给脚本即可。这样的话，应用程序有可能会将下面的事件传递给脚本：</p>
<p class="code">
	Private Sub cboCombo_Click()<br />
	objScript.Run &quot;cboCombo_Click&quot;<br />
	End Sub<br />
	Private Sub txtText_KeyPress(Index As Integer, KeyAscii As Integer)<br />
	KeyAscii = objScript.Run(&quot;txtText_KeyPress&quot;,Index, KeyAscii)<br />
	End Sub</p>
<p>
	如上面的示例所示，事件被直接传递给脚本，也可以选择将事件产生的参数一起传送给脚本。因为在某些情况下，可能需要修改某个参数。事件处理过程应该看成是一个函数，可以返回修改后的值。这可能是修改这种参数的最简单的方式。不过，这个功能并不是应用程序必须具有的。下面这个包含在脚本中的函数可以将文本框中输入的所有字符都转换成大写。</p>
<p class="code">
	Function txtText_KeyPress(Index , KeyAscii)<br />
	txtText_KeyPress = Asc(Ucase(Chr(KeyAscii)))<br />
	End Function</p>
<p>
	上述方法和VB代码中使用的方法有少许不同，因为即使以引用的方式(一般来说，VB代码应该是KeyAscii = Asc(Ucase(Chr(KeyAscii))))来传递KeyAscii的值，脚本都不会更新这个参数在原有VB代码中的值。这样，我们将事件处理程序从过程更改为函数，就实现了一种简单的变通。</p>
<p>
	可以不执行默认的事件处理程序，而是在脚本中提供另一个可选的事件处理程序。如果脚本中没有成员过程，就会发生错误，对于脚本中不包含恰当的具名过程的情况来说，这样就提供了忽略事件或提供默认事件的机会。下面的示例显示了最简单的错误抑制方法，允许创建默认的事件处理程序。此外，如果关闭错误处理程序(使用On Error Resume Next)，脚本就必须包含适当的具名过程，并具有正确数量的参数。</p>
<p class="code">
	Private Sub cboCombo_Click()<br />
	On Error Resume Next<br />
	objScript.Run &quot;cboCombo_Click&quot;<br />
	If Err = 0 Then Exit Sub<br />
	&#39; default event handler goes here<br />
	...End Sub</p>
<p>
	应用程序的具体细节取决于脚本自身，所以下面的示例显示脚本中只包含cboCombo_Click过程的部分实现，并没有将整个代码清单全部复制进来。</p>
<p>
	关键的控件被重置之后，设置标签的值，以及对应于CLE DB类型的连接字符串的文本。</p>
<p class="code">
	Sub cboCombo_Click()<br />
	Dim strComboSelection, strTmp<br />
	&#39; Clean Up in case this was pressed already<br />
	Form.cmdRegister.Enabled = False<br />
	Form.cmdProcess.Enabled = True<br />
	Form.lblRegistry.Caption = &quot;&quot;<br />
	For i = 0 To 5<br />
	Form.lblLabel(i).Visible = False<br />
	Form.txtText(i).Visible = False<br />
	Next<br />
	strComboSelection = _<br />
	Trim(Form.cboCombo.List(Form.cboCombo.ListIndex))<br />
	Select Case strComboSelection<br />
	Case &quot;OLE DB&quot;<br />
	For i = 0 To 4<br />
	Form.lblLabel(i).Visible = True<br />
	Form.txtText(i).Visible = True<br />
	Next<br />
	Form.lblLabel(0).Caption = &quot;Provider=&quot;<br />
	Form.lblLabel(1).Caption = &quot;Data Source=&quot;<br />
	Form.lblLabel(2).Caption = &quot;Initial Catalog=&quot;<br />
	Form.lblLabel(3).Caption = &quot;User ID=&quot;<br />
	Form.lblLabel(4).Caption = &quot;Password=&quot;<br />
	Form.txtText(0).Text = &quot;SQLOLEDB&quot;<br />
	Form.txtText(1).Text = &quot;DATABOX&quot;<br />
	Form.txtText(2).Text = &quot;MyAppDB&quot;<br />
	Form.txtText(3).Text = &quot;Student&quot;<br />
	Form.txtText(4).Text = &quot;teacher&quot;<br />
	[...]<br />
	End Select<br />
	strTmp = &quot;Please Fill In Remaining Values in the available&quot;<br />
	strTmp = strTmp &amp; &quot; text boxes. &quot; &amp; vbCrLf<br />
	strTmp = strTmp &amp; &quot;You may press &quot;&quot;Proceed&quot;&quot; button, or&quot;<br />
	strTmp = strTmp &amp; &quot; change the connection method again. &quot;<br />
	strTmp = strTmp &amp; &quot;Leaving User ID empty will leave out&quot;<br />
	strTmp = strTmp &amp; &quot; user infromation from registry&quot;<br />
	Form.lblExplanation = strTmp<br />
	End Sub</p>
<p>
	应用程序的剩余部分用于响应终端用户的事件，并建立核心应用程序所请求的连接字符串，启用和关闭控件，以及根据场景不同修改表单上的值。最后提到的这个动作是直接由应用程序本身执行的；基于存储在表单上某一标签中的字符串将一个值写入注册表。</p>
<p>
	这个小应用程序可以进一步扩充，利用一些脚本提供类似于向导的功能，相应脚本的编写也是很简单的。</p>
<h3>
	21.10&nbsp; 小结</h3>
<p>
	脚本控件是由Microsoft提供的免费控件，使VB 6、.NET或其它支持COM的应用程序能够提供脚本引擎。使用脚本引擎可以进行简单的动态表达式计算，也可以实现成熟的宏语言插件，用于自动化应用程序。</p>
<p>
	这一章讨论了下面这些内容：</p>
<p style="margin-left: 37.45pt">
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 脚本控件的概念<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为什么说脚本控件是Visual Basic 6和.NET应用程序的有益补充<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为什们要使用脚本控件(为什么不使用脚本控件)<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 脚本控件的对象模型，包括属性、方法和事件<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 错误处理和调试<br />
	●&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 通过两个范例工程演示了脚本控件在VB.NET和VB 6中的使用</p>

</body>
</html>
